package service

import (
	"context"
	"errors"
	"fmt"
	"log"
	"strconv"
	"time"

	"github.com/ammyhaber/seckill/service/order/dao"
	"github.com/ammyhaber/seckill/service/order/model"
	"github.com/ammyhaber/seckill/service/order/mq"
)

// OrderServiceWithMQ 基于消息队列的订单服务实现
type OrderServiceWithMQ struct {
	orderDAO          *dao.OrderDAO
	inventoryProducer *mq.InventoryProducer
}

// NewOrderServiceWithMQ 创建基于消息队列的订单服务
func NewOrderServiceWithMQ(orderDAO *dao.OrderDAO, inventoryProducer *mq.InventoryProducer) *OrderServiceWithMQ {
	return &OrderServiceWithMQ{
		orderDAO:          orderDAO,
		inventoryProducer: inventoryProducer,
	}
}

// CreateOrderWithMQ 创建订单（基于消息队列实现库存一致性）
func (s *OrderServiceWithMQ) CreateOrderWithMQ(ctx context.Context, req *model.OrderCreateRequest) (*model.Order, error) {
	// 参数校验
	if req.UserID <= 0 || req.ProductID <= 0 || req.Quantity <= 0 {
		return nil, errors.New("参数无效")
	}

	// 1. 生成订单ID
	orderID := s.generateOrderID(req.UserID)

	// 2. 发送锁定库存消息（异步锁定库存）
	err := s.inventoryProducer.SendLockInventoryMessage(ctx, fmt.Sprintf("%d", orderID), req.ProductID, req.Quantity, req.UserID)
	if err != nil {
		return nil, fmt.Errorf("发送锁定库存消息失败: %w", err)
	}

	// 当前时间
	now := time.Now()
	// 设置过期时间（15分钟后）
	expireTime := now.Add(15 * time.Minute)

	// 3. 创建订单（状态为待支付）
	order := &model.Order{
		ID:         orderID,
		UserID:     req.UserID,
		ProductID:  req.ProductID,
		Quantity:   req.Quantity,
		Status:     model.OrderStatusPending, // 待支付状态
		ExpireTime: &expireTime,
		CreatedAt:  now,
		UpdatedAt:  now,
	}

	// 4. 保存订单到数据库
	err = s.orderDAO.CreateOrder(order)
	if err != nil {
		// 订单创建失败，发送取消库存锁定消息
		go func() {
			cancelCtx := context.Background()
			if cancelErr := s.inventoryProducer.SendCancelInventoryMessage(cancelCtx, fmt.Sprintf("%d", orderID), req.ProductID, req.Quantity, req.UserID); cancelErr != nil {
				log.Printf("发送取消库存锁定消息失败: %v\n", cancelErr)
			}
		}()
		return nil, fmt.Errorf("创建订单失败: %w", err)
	}

	// 5. 启动异步检查库存锁定状态的任务
	go s.checkInventoryLockStatus(orderID, req.ProductID, req.Quantity, req.UserID)

	return order, nil
}

// checkInventoryLockStatus 检查库存锁定状态
func (s *OrderServiceWithMQ) checkInventoryLockStatus(orderID int64, productID int64, quantity int, userID int64) {
	// 创建上下文
	ctx := context.Background()

	// 等待一段时间（例如3秒）
	time.Sleep(3 * time.Second)

	// 查询订单状态
	order, err := s.orderDAO.GetOrderByID(orderID, userID)
	if err != nil {
		log.Printf("查询订单状态失败: %v\n", err)
		return
	}

	// 如果订单仍然是待支付状态但过期了，则取消订单
	if order != nil && order.Status == model.OrderStatusPending && order.ExpireTime != nil && order.ExpireTime.Before(time.Now()) {
		// 更新订单状态为已取消
		err = s.orderDAO.UpdateOrderStatus(orderID, userID, model.OrderStatusCanceled)
		if err != nil {
			log.Printf("更新订单状态失败: %v\n", err)
		}

		// 发送取消库存锁定消息
		err = s.inventoryProducer.SendCancelInventoryMessage(ctx, fmt.Sprintf("%d", orderID), productID, quantity, userID)
		if err != nil {
			log.Printf("发送取消库存锁定消息失败: %v\n", err)
		}
	}
}

// PayOrderWithMQ 支付订单（基于消息队列确认库存扣减）
func (s *OrderServiceWithMQ) PayOrderWithMQ(ctx context.Context, req *model.OrderPayRequest) error {
	// 参数校验
	if req.OrderID <= 0 || req.UserID <= 0 {
		return errors.New("参数无效")
	}

	// 1. 查询订单
	order, err := s.orderDAO.GetOrderByID(req.OrderID, req.UserID)
	if err != nil {
		return fmt.Errorf("查询订单失败: %w", err)
	}

	if order == nil {
		return errors.New("订单不存在")
	}

	// 2. 验证订单所有者
	if order.UserID != req.UserID {
		return errors.New("无权操作此订单")
	}

	// 3. 检查订单状态
	if order.Status != model.OrderStatusPending {
		return errors.New("订单状态不正确，无法支付")
	}

	// 4. 更新订单状态为已支付
	err = s.orderDAO.UpdateOrderStatus(req.OrderID, req.UserID, model.OrderStatusPaid)
	if err != nil {
		return fmt.Errorf("更新订单状态失败: %w", err)
	}

	// 5. 发送确认库存扣减消息
	err = s.inventoryProducer.SendConfirmInventoryMessage(ctx, fmt.Sprintf("%d", req.OrderID), order.ProductID, order.Quantity, order.UserID)
	if err != nil {
		// 发送消息失败，记录日志，但不影响订单支付结果
		// 可以通过定时任务重试发送
		log.Printf("发送确认库存扣减消息失败: %v\n", err)
	}

	return nil
}

// CancelOrderWithMQ 取消订单（基于消息队列取消库存锁定）
func (s *OrderServiceWithMQ) CancelOrderWithMQ(ctx context.Context, req *model.OrderCancelRequest) error {
	// 参数校验
	if req.OrderID <= 0 || req.UserID <= 0 {
		return errors.New("参数无效")
	}

	// 1. 查询订单
	order, err := s.orderDAO.GetOrderByID(req.OrderID, req.UserID)
	if err != nil {
		return fmt.Errorf("查询订单失败: %w", err)
	}

	if order == nil {
		return errors.New("订单不存在")
	}

	// 2. 验证订单所有者
	if order.UserID != req.UserID {
		return errors.New("无权操作此订单")
	}

	// 3. 检查订单状态
	if order.Status != model.OrderStatusPending {
		return errors.New("订单状态不正确，无法取消")
	}

	// 4. 更新订单状态为已取消
	err = s.orderDAO.UpdateOrderStatus(req.OrderID, req.UserID, model.OrderStatusCanceled)
	if err != nil {
		return fmt.Errorf("更新订单状态失败: %w", err)
	}

	// 5. 发送取消库存锁定消息
	err = s.inventoryProducer.SendCancelInventoryMessage(ctx, fmt.Sprintf("%d", req.OrderID), order.ProductID, order.Quantity, order.UserID)
	if err != nil {
		// 发送消息失败，记录日志，定时任务重试
		log.Printf("发送取消库存锁定消息失败: %v\n", err)
		return fmt.Errorf("发送取消库存锁定消息失败: %w", err)
	}

	return nil
}

// 生成订单ID
func (s *OrderServiceWithMQ) generateOrderID(userID int64) int64 {
	// 简单实现：时间戳 + 用户ID后四位
	timestamp := time.Now().UnixNano() / 1e6 // 毫秒时间戳
	orderIDStr := fmt.Sprintf("%d%04d", timestamp, userID%10000)
	orderID, _ := strconv.ParseInt(orderIDStr, 10, 64)
	return orderID
}
